﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
using System.Collections;
using System.Diagnostics;

namespace Maxel
{
    public class TrackDataGridViewColumn : DataGridViewColumn
    {
        public TrackDataGridViewColumn()
        {
            this.ValueType = typeof(object);
            this.HeaderCell = headerCell;
           // HeaderCell.ReadOnly = true;
            //headerCell. 
            //HeaderCellCore.Visible = true; 
        }
        TrackDataGridViewHeaderCell headerCell = new TrackDataGridViewHeaderCell();

        public override DataGridViewCell CellTemplate
        {
            get
            {
                TrackDataGridViewCell cell = new TrackDataGridViewCell();
                //cell.Add(100);
                //cell.Add(50);
                return cell;
            }
            set
            {
                
                base.CellTemplate = value;
            }
        }

        private bool _dataGridViewEventsSet;
        protected override void OnDataGridViewChanged()
        {
            base.OnDataGridViewChanged();
            if (this.DataGridView != null && !_dataGridViewEventsSet)
            {
                DataGridView.Paint += new PaintEventHandler(DataGridView_Paint);
                //DataGridView.ColumnHeaderMouseClick += new DataGridViewCellMouseEventHandler(DataGridView_ColumnHeaderMouseClick);
                DataGridView.MouseDown += new MouseEventHandler(DataGridView_MouseDown);
                DataGridView.MouseMove += new MouseEventHandler(DataGridView_MouseMove);
                DataGridView.MouseUp  += new MouseEventHandler(DataGridView_MouseUp);
                DataGridView.Scroll += new ScrollEventHandler(DataGridView_Scroll); 


                DataGridView.CellPainting += new DataGridViewCellPaintingEventHandler(DataGridView_CellPainting);
                _dataGridViewEventsSet = true;
            }
        }

        void DataGridView_Scroll(object sender, ScrollEventArgs e)
        {
            ((DataGridView)sender).Invalidate();
        }
        bool _isMouseDown = false;
        void DataGridView_MouseDown(object sender, MouseEventArgs e)
        {
            HandleMouse(e);
            _isMouseDown = true;

        }
        void DataGridView_MouseMove(object sender, MouseEventArgs e)
        {
            if (!_isMouseDown)
                return;
            HandleMouse(e);
        }
        void DataGridView_MouseUp(object sender, MouseEventArgs e)
        {
            HandleMouse(e);
            _isMouseDown = false;

        }
        private void HandleMouse(MouseEventArgs e)
        {
            DataGridView.HitTestInfo info = DataGridView.HitTest(e.X, e.Y);
            if (info.ColumnIndex != this.Index)
                return;
            if (info.RowIndex >= 0)
                return;


            dataGridViewIndicatorX = e.X;
            DataGridView.Invalidate();
        }
        void DataGridView_MouseClick(object sender, MouseEventArgs e)
        {
            //if (e.ColumnIndex != this.Index)
            //    return;

            DataGridView.HitTestInfo info  = DataGridView.HitTest(e.X, e.Y);
            if (info.ColumnIndex != this.Index)
                return;

            dataGridViewIndicatorX = e.X;
            DataGridView.Invalidate();
        }
        int dataGridViewIndicatorX = 0;
        int timelineIndicatorX = 0;
        void DataGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            //if (e.ColumnIndex !=this.Index )
            //    return;

            //timelineIndicatorX = e.X;
            //DataGridView.Invalidate();
        } 
        void DataGridView_Paint(object sender, PaintEventArgs e)
        {
            //this.HeaderCell. 
            int x =0;
            if (timelineIndicatorX >= 0)
            {
                x = dataGridViewIndicatorX;
            }
            e.Graphics.DrawLine(Pens.Black, new Point(x, 0), new Point(x, ((DataGridView)sender).Height));
        }

        
        public string StartColor { get; set; }
        public string EndColor { get; set; }
        public string Duration { get; set; }


        public delegate void SelectedFrameChangedHandler(object sender,SelectedFrameChangedEventArgs e) ;
        public event SelectedFrameChangedHandler SelectedFrameChanged;

        internal void OnSelectedFrameChanged(object frame)
        {
            if (SelectedFrameChanged != null)
            {
                SelectedFrameChanged(this.DataGridView, new SelectedFrameChangedEventArgs() { Frame = frame }); 
            }
        }

        public delegate void FrameEditingHandler(object sender, FrameEditingEventArgs e);
        public event FrameEditingHandler FrameEditing;

        internal bool OnFrameEditing(object frame,string context)
        {
            if (FrameEditing != null)
            {
                FrameEditingEventArgs args = new FrameEditingEventArgs() { Frame = frame, Context = context };
                FrameEditing(this.DataGridView, args);
                return !args.Cancel;
            }
            return false;
        }

        const int INITIAL_SCALE = 200;

        public int InitialScale
        {
            get { return INITIAL_SCALE; }
        }

        float _scaleFactor = 100;

        public float ScaleFactor
        {
            get { return _scaleFactor; }
        }


        public void Scale(int scaleFactor)
        {
            _scaleFactor = scaleFactor;
            this.DataGridView.InvalidateColumn(this.Index);    
        }

        private static List<double> _layers = new List<double>()
        {
           // 0.01,0.05,0.1,0.2,0.5,1,5,10,30,60
            0.01,0.1,0.5,1,5,10,30,60
        }; 
        private Hashtable _timelineItems = new Hashtable();
        [DebuggerDisplay("Width={Width}")]
        public struct TimeLineItem
        {
            public int Layer { get; set; }
            public double Width { get; set; }
            public string Value { get; set; }
        }
        private string GetUnitByLayer(int layer)
        {
            double value = _layers[layer];

            if (value >= 1 && value < 60)
                return "s";
            else if (value == 60)
                return "m";
            else return string.Empty;

        }
        private float GetTimeUnit(float seconds)
        {
            float result = 0f;
            if (seconds >= 0 && seconds < 1)
            {
                result = seconds;
            }
            else if (seconds >= 1 && seconds < 60)
            {
                result = seconds;
            }
            else if (seconds >= 60 && seconds < 60 * 60 && seconds % 60 == 0)
            {
                result = seconds / 60;
            }
            else if (seconds >= 60 * 60 && seconds < 60 * 60 * 24 && seconds % (60 * 24) == 0)
            {
                result = seconds / (60 * 24);//seconds / (60 * 24);
            }
            else return seconds;//(float)Math.Round((double)result, 2);

            return result;

        }
        private double GetWidthByLayer(int layer)
        {
            return (double)(ScaleFactor * _layers[layer]);
            //switch (layer )
            //{
            //    case 0:
            //        return ScaleFactor/5;
            //    case 1:
            //        return ScaleFactor;
            //    case 2:
            //        return ScaleFactor*60;
            //    //case 3:
            //    //	return 12000; 
            //    default:
            //        return ScaleFactor*10;
            //}

        }
        static Pen pen = Pens.Gray;

        void DataGridView_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
        {
            if (e.ColumnIndex != this.Index)
                return;

            if (e.RowIndex != -1)
                return;
            this.HeaderText = "";

            //base.OnPaint(e);
            _timelineItems.Clear();
            //_timelineItemsDiscionary.Values.OrderBy<TimeLineItem, float>(item->item.);
            int length = this.Width;
            //int countOfMainLabels = (int)Math.Ceiling ((double)(length / 200));
            //int countOfAuxLabels = (int)Math.Ceiling((double)(length / 100));


            int numberOfLayers = _layers.Count;
            for (int i = 0; i < numberOfLayers; i++)
            {
                double width = GetWidthByLayer(i);
                if (width < 5)
                    continue;
                int countOfLabels = (int)Math.Ceiling(((double)length / width));
                for (int j = 0; j < countOfLabels; j++)
                {
                    TimeLineItem item = new TimeLineItem();
                    if (_timelineItems.ContainsKey(j * width))
                    {

                        item = (TimeLineItem)_timelineItems[j * width];

                        if (item.Layer < i)
                        {
                            _timelineItems.Remove(j * width);
                        }
                        //continue;
                    }
                    float time = GetTimeUnit((float)(j * width) / (float)ScaleFactor);
                    string timeString = (time == 0) ? time.ToString() : time + GetUnitByLayer(i);
                    TimeLineItem newItem = new TimeLineItem() { Layer = i, Width = j * width, Value = timeString };
                    _timelineItems.Add(j * width, newItem);
                }

            }
            Brush brush = Brushes.Black;

            //for (int i = 0; i < countOfMainLabels; i++)	
            //{
            //    SizeF stringSize = e.Graphics.MeasureString(i.ToString(), font);

            //    e.Graphics.DrawString(i.ToString(), font, brush, new Point((int)(i * 200-stringSize.Width/2)  , 5));
            //}
            IEnumerator each = _timelineItems.Values.GetEnumerator();
            int counter = 0;
            while (each.MoveNext())
            {
                //for (int i = 0; i < _timelineItems.Values.Count    ; i++)
                //{
                TimeLineItem item = (TimeLineItem)each.Current;
                //Pen pen = new Pen(Color.FromArgb(255 - item.Layer*2, 0, 0, 0));
                double x = item.Width+e.CellBounds.X  ; //+this.Margin.All *2 ;// - (float)stringSize.Width / 2f;
                double width = GetWidthByLayer(item.Layer);
                if (width > 5)
                {
                    double lineHeigth = (double)(item.Layer * 2 + 3f);
                    e.Graphics.DrawLine(pen, new PointF((float)x, e.ClipBounds.Height - (float)(lineHeigth)), new PointF((float)x, e.ClipBounds.Height));
                }
                if (width > 40)
                {
                    SizeF stringSize = e.Graphics.MeasureString(item.Value, e.CellStyle.Font);

                    if (item.Width == 0)
                        e.Graphics.DrawString(item.Value, e.CellStyle.Font, brush, new PointF((float)x, 2));
                    else
                        e.Graphics.DrawString(item.Value, e.CellStyle.Font, brush, new PointF((float)x - (float)(stringSize.Width / 2f), 2));
                }
                counter++;
                //}
            }
           // e.Graphics.DrawLine(pen, new PointF(CurrentXLocation, 0), new PointF(CurrentXLocation, this.Height));

        }


    }
    public class SelectedFrameChangedEventArgs:EventArgs 
    {
        public object Frame { get; set; }
    }
    public class FrameEditingEventArgs : CancelEventArgs
    {
        public object Frame { get; set; }
        public string Context { get; set; }

    }

}

